home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / process.c < prev    next >
C/C++ Source or Header  |  1996-03-28  |  6KB  |  281 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <signal.h>
  5. #include <linux/param.h>
  6. #include <limits.h>
  7. #include <time.h>
  8. #include "netconf.h"
  9. #include "../xconf/xconf.h"
  10. #include "netconf.m"
  11.  
  12. /*
  13.     Read the first line of a file
  14.     Return -1 if any error.
  15. */
  16. static int process_readfile (const char *path, char *buf, int sizebuf)
  17. {
  18.     int ret = -1;
  19.     // No error message signaled as "path" is a file under /proc/pid
  20.     // and the process may vanish while we are reading it.
  21.     FILE *fin = fopen (path,"r");
  22.     if (fin != NULL){
  23.         if (fgets (buf,sizebuf-1,fin)!=NULL){
  24.             ret = 0;
  25.         }
  26.         fclose (fin);
  27.     }
  28.     return ret;    
  29. }
  30.  
  31. struct PS_PROC {
  32.     char cmdline[256], user[10], cmd[40], state, ttyc[4];
  33.     int uid, pid, ppid, pgrp, session, tty, tpgid, utime, stime,
  34.     cutime, cstime, counter, priority, start_time, signal, blocked,
  35.     sigignore, sigcatch;
  36.     unsigned int flags, min_flt, cmin_flt, maj_flt, cmaj_flt, timeout,
  37.     it_real_value, vsize, rss, rss_rlim, start_code, end_code,
  38.     start_stack, kstk_esp, kstk_eip, wchan;
  39. };
  40. /*
  41.     Read the file /proc/pid/stat into the struct PS_PROC
  42.     Return -1 if any error.
  43. */
  44.  
  45. static int process_readstat(int pid, PS_PROC &_psp)
  46. {
  47.     int ret = -1;
  48.     char tmppath[PATH_MAX];
  49.     sprintf (tmppath,"/proc/%d/stat",pid);
  50.     char buf[PATH_MAX];
  51.     if (process_readfile (tmppath,buf,sizeof(buf))!=-1){        
  52.         PS_PROC psp;
  53.         sscanf(buf, "%d %s %c %d %d %d %d %d %u %u "
  54.             "%u %u %u %d %d %d %d %d %d %u "
  55.             "%u %d %u %u %u %u %u %u %u %u %u "
  56.             "%u %u %u %u\n",
  57.             &psp.pid, psp.cmd, &psp.state, &psp.ppid,
  58.             &psp.pgrp, &psp.session, &psp.tty, &psp.tpgid,
  59.             &psp.flags, &psp.min_flt, &psp.cmin_flt,
  60.             &psp.maj_flt, &psp.cmaj_flt,
  61.             &psp.utime, &psp.stime, &psp.cutime, &psp.cstime,
  62.             &psp.counter, &psp.priority, &psp.timeout,
  63.             &psp.it_real_value, &psp.start_time,
  64.             &psp.vsize, &psp.rss, &psp.rss_rlim,
  65.             &psp.start_code, &psp.end_code, &psp.start_stack,
  66.             &psp.kstk_esp, &psp.kstk_eip,
  67.             &psp.signal, &psp.blocked, &psp.sigignore, &psp.sigcatch,
  68.             &psp.wchan);
  69.         _psp = psp;
  70.         ret = 0;
  71.     }
  72.     return ret;
  73. }
  74.  
  75.  
  76. /*
  77.     Information about a process ID
  78. */
  79. PUBLIC PROC::PROC (int _pid, PROC *_next)
  80. {
  81.     next = _next;
  82.     pid = _pid;
  83.     path = NULL;
  84.     name = NULL;
  85.     char tmppath[PATH_MAX];
  86.     sprintf (tmppath,"/proc/%d/cmdline",_pid);
  87.     char buf[PATH_MAX];
  88.     PS_PROC psp;
  89.     if (process_readfile (tmppath,buf,sizeof(buf))!=-1){
  90.         if (sscanf (buf,"%s",tmppath)==1){
  91.             // Small patch for sendmail
  92.             char *pt = strchr(tmppath,':');
  93.             if (pt != NULL) *pt = '\0';
  94.             path = strdup(tmppath);
  95.         }
  96.     }else if (process_readstat(_pid,psp)!=-1){
  97.         strcpy (buf,psp.cmd[0] == '(' ? psp.cmd+1 : psp.cmd);
  98.         char *pt = strchr(buf,')');
  99.         if (pt != NULL) *pt = '\0';
  100.         path = strdup(buf);
  101.     }
  102.     if (path != NULL){
  103.         name = strrchr(path,'/');
  104.         if (name != NULL){
  105.             name++;
  106.         }else{
  107.             name = path;
  108.         }
  109.     }
  110. }
  111. PUBLIC PROC::~PROC ()
  112. {
  113.     free (path);
  114. }
  115. /*
  116.     Return the next PROC in the list or NULL.
  117. */
  118. PUBLIC PROC *PROC::getnext ()
  119. {
  120.     return next;
  121. }
  122. /*
  123.     Return != 0 if the information on the process was read properly.
  124. */
  125. PUBLIC int PROC::isok ()
  126. {
  127.     return path != NULL;
  128. }
  129.  
  130. /*
  131.     Return the path (command line) of a process
  132. */
  133. PUBLIC const char *PROC::getpath ()
  134. {
  135.     return path;
  136. }
  137. /*
  138.     Return the name (command line) of a process
  139. */
  140. PUBLIC const char *PROC::getname ()
  141. {
  142.     return name;
  143. }
  144. /*
  145.     Send a signal to the process.
  146. */
  147. PUBLIC int PROC::kill (int signo)
  148. {
  149.     int ret = 0;
  150.     if (!simul_ison()){
  151.         ret = ::kill (pid,signo);
  152.     }
  153.     return ret;
  154. }
  155. /*
  156.     Return the start time of a process.
  157.     Return -1 is the process is dead.
  158. */
  159. PUBLIC long PROC::getstarttime ()
  160. {
  161.     long ret = -1;
  162.     long uptime;
  163.     char buf[200];
  164.     if (process_readfile ("/proc/uptime",buf,sizeof(buf))!=-1){
  165.         uptime = atoi(buf);
  166.         PS_PROC psp;
  167.         if (process_readstat(pid,psp)!=-1){
  168.             long seconds = (((uptime * 100) - psp.start_time) / HZ);
  169.             ret = time(NULL) - seconds;
  170.         }
  171.     }
  172.     return ret;
  173. }
  174.  
  175. static PROC *first = NULL;
  176.  
  177. /*
  178.     Read all the process currently active and store for usage by
  179.     other process_function.
  180.     The info is kept for all process_find and isalive call. It
  181.     is flushed when process_read is called again.
  182. */
  183. int process_read()
  184. {
  185.     while (first != NULL){
  186.         PROC *next = first->getnext();
  187.         delete first;
  188.         first = next;
  189.     }
  190.     static char *cmd_ls = "/bin/ls /proc/*/cmdline 2>/dev/null";
  191.     FILE *fin = popen (cmd_ls,"r");
  192.     int nbproc = -1;
  193.     if (fin == NULL){
  194.         xconf_error (MSG_U(E_CANTEXEC,"Can't execute command %s\n"));
  195.     }else{
  196.         nbproc = 0;
  197.         char buf[PATH_MAX+1];
  198.         while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
  199.             if (buf[0] == '/'){
  200.                 int pid = atoi(buf+6);
  201.                 if (pid != 0){
  202.                     PROC *prc = new PROC (pid,first);
  203.                     if (prc->isok()){
  204.                         first = prc;
  205.                         nbproc++;
  206.                     }else{
  207.                         delete prc;
  208.                     }
  209.                 }
  210.             }
  211.         }
  212.         pclose (fin);
  213.     }
  214.     return nbproc;
  215. }
  216.  
  217. static PROC *process_find(const char *path, const char *name)
  218. {
  219.     PROC *ret = first;
  220.     while (ret != NULL){
  221.         const char *ppath = ret->getpath();
  222.         const char *pname = ret->getname();
  223.         if (strcmp(path,ppath)==0
  224.             || strcmp(name,pname)==0){
  225.             break;
  226.         }else{
  227.             ret = ret->getnext();
  228.         }
  229.     }
  230.     return ret;
  231. }
  232. /*
  233.     Check if a process is running at least once
  234.     Return -1 or the start time of this process.
  235. */
  236. PROC *process_find (const char *path)
  237. {
  238.     /* #Specification: process / lookup / strategy
  239.         When looking for a process, we search first for the exact path
  240.         (command line). If this fail, then we use the name only without
  241.         path. This should be safe enough to prevent mistake.
  242.     */
  243.     if (first == NULL) process_read ();
  244.     const char *name = strrchr (path,'/');
  245.     name = name == NULL ? path : name + 1;
  246.     PROC *ret = process_find (path,"");
  247.     if (ret == NULL) ret = process_find ("",name);
  248.     return ret;
  249. }
  250.  
  251. /*
  252.     Check if a process is running at least once
  253.     Return -1 or the start time of this process.
  254. */
  255. long process_isactive (const char *path)
  256. {
  257.     PROC *prc = process_find (path);
  258.     long ret = -1;
  259.     if (prc != NULL) ret = prc->getstarttime();
  260.     return ret;
  261. }
  262.  
  263. #ifdef TEST
  264.  
  265. int main (int argc, char *argv[])
  266. {
  267.     for (int i=1; i<argc; i++){
  268.         long start = process_isactive(argv[i]);
  269.         printf ("%s -> ",argv[i]);
  270.         if (start == -1){
  271.             printf ("nil\n");
  272.         }else{
  273.             printf ("%ld %s\n",start,ctime(&start));
  274.         }
  275.     }
  276.     return 0;
  277. }
  278.  
  279. #endif
  280.  
  281.